/*
 * Map.cpp
 *
 *	Version 1.0
 *  Created on: Sep 26, 2010
 *      Author: Mark Zmek
 *
 *  Copyright 2010 Michigan Technological University. All rights reserved.
 */

#include <iostream>
#include <fstream>
#include <string>
#include <math.h>
#include "SDL/SDL_image.h"

#include "Map.h"
#include "MapObstacle.h"

using namespace std;

/*
 * Creates a new map from a file.
 *
 * mapfile: The path to the map file to read from.
 */
Map::Map(string mapFile,  Renderer* render){

	renderer=render;

	ifstream input;
	input.open(mapFile.c_str());

	char c;
	c=input.peek();

	//skips past all the beginning notes until input reaches the rows and columns of the map in tiles
	while((c<'0' || c > '9') && !input.eof()){
		input.ignore(255,'\n');
		c=input.peek();
	}

	input>>rows;
	//goes to where the columns are defined
	c=input.peek();
	while((c<'0' || c > '9') && !input.eof()){
		input.ignore(1);
		c=input.peek();
	}
	input>>columns;


	//skips to where the height and width of each tile is defined
	c=input.peek();
	while((c<'0' || c > '9') && !input.eof()){
		input.ignore(255,'\n');
		c=input.peek();
	}

	input>>tileHeight;
	//goes to where the width is defined
	c=input.peek();
	while((c<'0' || c > '9') && !input.eof()){
		input.ignore(1);
		c=input.peek();
	}
	input>>tileWidth;


	//skips to where the number of images used in the map will be defined
	c=input.peek();
	while((c<'0' || c > '9') && !input.eof()){
		input.ignore(255,'\n');
		c=input.peek();
	}

	input>>numMapImages;
	mapImages=new MapTile*[numMapImages];

	//skips to where the image files and clip data are defined
	c=input.peek();
	while(c!='"' && !input.eof()){
		input.ignore(255,'\n');
		c=input.peek();
	}

	//holds the file path to the next image and the clipping data
	string * currentFilePath=new string();
	int cx,cy,cw,ch;

	for(int i=0;i<numMapImages;i++){
		input.ignore(1);//ignores the quotation mark that input should be pointing to
		input>>c;

		//reads in the file path to the image
		while(c!='"' && !input.eof()){
			*currentFilePath+=c;
			input>>c;
		}

		//skips to the clipping data or the end of the line if there is no clipping data
		c=input.peek();
		while((c<'0' || c > '9')&& c!='\n' && c!='#' &&!input.eof()){
			input.ignore(1);
			c=input.peek();
		}

		//reads in the clipping data
		if(c>='0' && c<='9'){
			//reads in the x coordinate of the clipping
			input>>cx;

			//skips to where the y coordinate of the clipping is defined and reads it in
			c=input.peek();
			while((c<'0' || c > '9')&& c!='\n' &&!input.eof()){
				input.ignore(1);
				c=input.peek();
			}
			input>>cy;

			//skips to where the width of the clipping is defined and reads it in
			c=input.peek();
			while((c<'0' || c > '9')&& c!='\n' &&!input.eof()){
				input.ignore(1);
				c=input.peek();
			}
			input>>cw;

			//skips to where the height of the clipping is defined and reads it in
			c=input.peek();
			while((c<'0' || c > '9')&& c!='\n' &&!input.eof()){
				input.ignore(1);
				c=input.peek();
			}
			input>>ch;

			//skips to the next image data
			input.ignore(255,'\n');

			cout<<"clipData: "<<cx<<","<<cy<<","<<cw<<","<<ch<<endl;//TODO remove debug code
		}
		//there is no clipping data so we skip to the next image data
		else{
			input.ignore(255,'\n');
		}

		cout<<"CPF: "<<*currentFilePath<<endl;//TODO remove debug code
		//loads in the map image
		mapImages[i]=new MapTile();
		mapImages[i]->tileBackground=renderer->loadImage(*currentFilePath);
		mapImages[i]->tileTexture=renderer->createTexture(mapImages[i]->tileBackground);

		delete currentFilePath;
		currentFilePath=new string();
		//skips to the data for the next image
	}


	//skips to where the number of obstacles in the map will be defined
	c=input.peek();
	while((c<'0' || c > '9') && !input.eof()){
		input.ignore(255,'\n');
		c=input.peek();
	}

	input>>numObstacles;
	obstacles=new MapObstacle*[numObstacles];


	//skips to where the tile data and obstacle locations are defined
	c=input.peek();
	while((c<'0' || c > '9') && !input.eof()){
		input.ignore(255,'\n');
		c=input.peek();
	}


	//this creates a 2D array of surface pointers, tileBackgrounds[row][column]
	mapTiles=new MapTile**[rows];
	for(int i=0; i<rows; i++){
		mapTiles[i]=new MapTile*[columns];
	}
	for(int x=0;x<rows;x++){
		for(int y=0;y<columns;y++){
			mapTiles[x][y]=NULL;
		}
	}

	//the current index in the obstacle array to add to
	int currObs=0;
	//the integer representing the next piece of tile data
	int dataIn=-1;

	//reads down the lines
	for(int j=0; j<rows; j++){

		//reads across each line
		for(int k=0; k<columns; k++){
			//reads in which image to use as the background image
			input>>dataIn;

			//initializes the tile in row j and column k
			mapTiles[j][k]=new MapTile();
			mapTiles[j][k]->tileTexture=mapImages[dataIn]->tileTexture;
			mapTiles[j][k]->tileBackground=mapImages[dataIn]->tileBackground;
			mapTiles[j][k]->position=new SDL_Rect();
			mapTiles[j][k]->position->x=k*tileWidth;
			mapTiles[j][k]->position->y=j*tileHeight;
			mapTiles[j][k]->position->w=tileWidth;
			mapTiles[j][k]->position->h=tileHeight;

			//goes to where the obstacle image is defined
			c=input.peek();
			while((c<'0' || c > '9')&& c!='-' &&!input.eof()){
				input.ignore(1);
				c=input.peek();
			}
			input>>dataIn;
			//creates an obstacle at the current tile if there is supposed to be one
			if(dataIn!=-1){
				MapTile* obstacleTile=new MapTile();
				obstacleTile->tileTexture=mapImages[dataIn]->tileTexture;
				obstacleTile->tileBackground=mapImages[dataIn]->tileBackground;
				obstacleTile->position=new SDL_Rect();
				obstacleTile->position->x=k*tileWidth;
				obstacleTile->position->y=j*tileHeight;
				obstacleTile->position->w=tileWidth;
				obstacleTile->position->h=tileHeight;
				obstacles[currObs]=new MapObstacle(j,k,obstacleTile);

				currObs++;
			}

			c=input.peek();
			while((c<'0' || c > '9')&& c!='-' &&!input.eof() && k<columns-1){
				input.ignore(1);
				c=input.peek();
			}

		}
//*		//skips to where the next line of tile data
		c=input.peek();
		while((c<'0' || c > '9') && !input.eof()){
			input.ignore(255,'\n');
			c=input.peek();
		}//*/
	}//end of reading in the tile data loop

	currPos=new SDL_Rect();
	currPos->w=tileWidth;
	currPos->h=tileHeight;

	//TODO remove debug code
/*
	c=input.peek();
	cout<<c<<" "<<input.eof()<<endl;
	cout<<columns<<endl;
	cout<<rows<<endl;
	cout<<tileWidth<<endl;
	cout<<tileHeight<<endl;
	cout<<numObstacles<<endl;//*/
/*
	for(int i=0;i<numObstacles;i++){
		cout<<obstacles[i]->getXPos()<<" "<<obstacles[i]->getYPos()<<",";
	}
	cout<<endl;//*/
/*
	for(int x=0;x<rows;x++){
		for(int y=0;y<columns;y++){
			cout<<mapTiles[x][y]->position->x<<" "<<mapTiles[x][y]->position->y<<";";
		}
		cout<<endl;
	}//*/
	delete currentFilePath;

	input.close();
}//end of constructor

Map::~Map(){
//*
	if(mapImages!=0){
		for(int i=0;i<numMapImages;i++){
			if(mapImages[i]->position != NULL)
				delete mapImages[i]->position;
			if(mapImages[i]->tileBackground != NULL)
				SDL_FreeSurface(mapImages[i]->tileBackground);
			delete mapImages[i];
		}
		delete [] mapImages;
	}//*/
//*
	if(obstacles!=0){
		for(int i=0;i<numObstacles;i++){
			delete obstacles[i];
		}
		delete [] obstacles;
	}//*/
//*
	if(mapTiles!=0){
		//the surfaces were already freed under mapImages
		for(int x=0;x<rows;x++){
			for(int y=0;y<columns;y++){
				delete mapTiles[x][y]->position;
				delete mapTiles[x][y];
			}
			delete [] mapTiles[x];
		}
		delete [] mapTiles;
	}//*/
	delete currPos;
}//end of destructor

/**
 * Draws the map on the screen.
 */
void Map::drawMap(){
	for(int x=0;x<rows;x++){
		for(int y=0;y<columns;y++){
			renderer->drawSurface(mapTiles[x][y]->position,0,mapTiles[x][y]->tileTexture);
		}
	}
	for(int i=0;i<numObstacles;i++){
		renderer->drawSurface(obstacles[i]->getTile()->position,0,obstacles[i]->getTile()->tileTexture);
	}
}

/**
 * Draws part of the map on the screen.
 *
 * startX is the x coordinate of the upper right corner of the screen.
 * startY is the y coordinate of the upper right corner of the screen.
 * endX is the x coordinate of the lower left corner of the screen.
 * endY is the y coordinate of the lower left corner of the screen.
 */
void Map::drawMap(int startX, int startY){
	int startColumn=(int)startX/tileWidth;
	int endColumn=(int)ceil((startX+renderer->getScreenWidth())/(float)tileWidth);

	int startRow=(int)startY/tileHeight;
	int endRow=(int)ceil((startY+renderer->getScreenHeight())/(float)tileHeight);

//	cout<<renderer->getScreenWidth()<<" "<<renderer->getScreenHeight()<<endl;

	for(int x=startRow;x<endRow;x++){
		for(int y=startColumn;y<endColumn;y++){
			currPos->x=y*tileWidth-startX;
			currPos->y=x*tileHeight-startY;
			renderer->drawSurface(currPos,0,mapTiles[x][y]->tileTexture);
		}
	}
	int obsColumn;
	int obsRow;
	for(int i=0;i<numObstacles;i++){
		obsColumn=obstacles[i]->getTile()->position->x/tileWidth;
		obsRow=obstacles[i]->getTile()->position->y/tileHeight;
		if(obsRow>=startRow && obsRow<=endRow && obsColumn>=startColumn && obsColumn<=endColumn){
			currPos->x=obstacles[i]->getTile()->position->x-startX;
			currPos->y=obstacles[i]->getTile()->position->y-startY;
			renderer->drawSurface(currPos,0,obstacles[i]->getTile()->tileTexture);
		}
	}
}

/**
 * Gets a pointer to the tile background.
 */
MapTile* Map::getTile(int x,int y){
	return mapTiles[x][y];
}

/**
 * Gets a pointer to the obstacle.
 */
MapObstacle* Map::getObstacle(int i){
	return obstacles[i];
}

int Map::getNumObstacles(){
	return numObstacles;
}

int Map::getNumRows(){
	return rows;
}

int Map::getNumColumns(){
	return columns;
}


int Map::getTileWidth(){
	return tileWidth;
}

int Map::getTileHeight(){
	return tileHeight;
}

int Map::getMapWidth(){
	return tileWidth*columns;
}

int Map::getMapHeight(){
	return tileHeight*rows;
}
